# coding: utf8
"""
RPA 流程制作中能了解到的 Python 基础知识？
https://support.i-search.com.cn/article/1677207097115
"""

# # **数值**`int`、`float`
# 整数
lv_int = 1
# 负数
lv_int2 = -1
# 小数
lv_float = 1.0

# # **字符串**`str`
# 单行（单引号）
lv_str = 'abc123你好(){}"...",-=+@!;'
# 多行字符串
lv_str1 = '''这是第1行
    这是第"2"行
    。。。
    第'n'行
'''

# 单双引号注意点：
print(
    '（"双引号在里"）',
    "（'单引号在里'）",
    '''（"双引号在里"，'单引号在里'）'''
)

# # 元组`tuple`
# 一组 ** 固定的 ** 有序数据（数组）
lv_tuple = (1, 0, 1, 'a', 'b', 'c')
# 访问元素：
print(lv_tuple[0], lv_tuple[2])

#  # **列表**`list`
# 一组 ** 可变的 ** 有序数据（数组）
lv_list = [1, 0, 1, 'a', 'b', 'c']
# 访问元素：
print(lv_list[-1], lv_list[-2])

# # 集合`set`
# 一组 ** 无重复的 ** 可变无序数据（数组）
lv_set = {1, 0, 'a', 'b', 'c'}

# # **字典**`dict`
# `键`→`值`对应的 ** 可变无序的 ** 数据（哈希表）
lv_dict = {'a': 1, 0: 'b', 1: 'c'}
# 访问键值
print(lv_dict['a'], lv_dict[0])

# # 查看变量数据和类型以及转换？（常见函数）
# `print`函数
print(lv_int, type(lv_int))

# `repr`函数
print(repr(lv_int), type(repr(lv_int)))

# `type`函数
print(type(lv_int))

# 类型转换
print(type(int(float('1.0'))))
print(type(str(lv_int)))
print(list(lv_str))
print(dict(a=1, b=2, c=3))

# # 默认值中拼接其他变量（字符串格式化）
# 普通字符串拼接
v_f = f'拼接{lv_int}和{lv_str}。'

# 文件路径拼接
lv_rf = rf'C:\{lv_int}\a.doc'
# 建议“针对专有体系”（系统路径）的字符串处理时，使用专有库，如自带的`os.path`库：
import os.path

lv_path = os.path.join('C:\\', str(lv_int), 'a.doc')
print(lv_rf, lv_path)

# # 不同条件执行不同流程（IF分支）
# 分支条件怎么写？
# 判断输入的个位数是否大于5
import random

lv_number_09 = random.randint(0, 9)
if lv_number_09 > 5:
    print(f"数字{lv_number_09}大于5")
elif lv_number_09 == 5:
    print(f"数字{lv_number_09}等于5")
else:
    print(f"数字{lv_number_09}小于5")

# 这条分支什么都不做（pass）
if lv_number_09 >= 5:
    pass
else:
    print(f"数字{lv_number_09}小于5")

# 结合变量赋值（if...else...）
lv_bl = '大' if lv_number_09 > 5 else '小'
print(lv_bl)

# 其他常见的逻辑条件写法
# 包含
print(1 in [1, 2, 3])
# 不包含
print(1 not in [1, 2, 3])
# 等于
print(1 == 1)
# 不等于
print(1 != 1)
# 是‘真’
print(0 is True)
# 是‘假’
print(0 is False)
# 是‘空’
print(0 is None)
# 等于‘空字符’
print(0 == '')

# # 取出一组数据中的每一个元素（For循环）
# 除了手动生成一个列表集合外，还可以使用`range()`函数
print([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(range(10)))
print(list(range(10, 20)))

# 逐个取出0-9的数字
for i in range(10):
    # 输出
    print(i)

# 逐个取出abc的序号和值
for number, value in enumerate(['a', 'b', 'c']):
    # 输出
    print(number, value)

# 跳过特定元素（continue）
for i in range(10):
    # 如果是奇数则跳过
    if i % 2:
        continue
    print(i)

# 找到想要的元素则结束循环（break）
for i in range(10):
    # 如果超过5则退出，只要0-5的数字
    if i > 5:
        break
    print(i)

# # 多执行几次直到成功再继续（While循环）
# 设定结束条件（while True）

# 当不满足i < 5时则结束循环，继续下面的代码
i = 0
while i < 5:
    print(i)
    i = i + 1
print(i)

# 执行到一半重头开始（continue）
# 在满足`i < 5`条件前提下，当变量`i == 3`时则不输出变量
i = 0
while i < 5:
    i = i + 1
    if i == 3:
        continue
    print(i)
print(i)

# 提前触发结束继续下面的流程（break）
# 在满足`i < 5`条件前提下，当变量`i == 3`时则不输出接下来的变量
i = 0
while i < 5:
    i = i + 1
    if i == 3:
        break
    print(i)
print(i)

# 随机出一个0-9的数字
import random

print(random.randint(0, 9))

# 试一试，如果没报错最好（except）
# 使用1 / 一个随机数，如果分母是0则会报错
try:
    number = random.randint(0, 9)
    print(number, 1 / number)
except Exception as e:
    print(e)
    raise Exception("分母不能为0")
finally:
    print(f"分母: {number}")


# 添加名为sum和inc两个【全局函数】
def sum(a, b):
    """求和"""
    return a + b


def inc(i):
    """递增"""
    return i + 1


# # 使用代码块对常用数据快速处理（字符串、列表、字典）
# # 字符串方法
lv_str = ' i-search iS-RPA '

# 字符替换（去除全部空格）
print(lv_str.replace(" ", ""))  # 输出'i-searchiS-RPA'

# 去除首尾空格（还有对应的l左边和r右边空格）
print(lv_str.strip())  # 输出'i-search iS-RPA'

# 分割字符串为列表，默认按空格分割，可以指定分隔符
print(lv_str.split())  # 输出['i-search', 'iS-RPA']
print(lv_str.split(" "))  # 输出['', 'i-search', 'iS-RPA', '']

# 将字符串统一转为小写lower或大写upper，降低字符串比较错误
print("aBc".lower() == "abc")  # 返回True

# 判断字符串以什么内容开头startswith或结尾endswith（比如判断文件格式）
print("a.docx".endswith(".docx"))  # 返回True

# 字符串间拼接
r, p, a = 'R', 'P', 'A'
print(r + '-' + p + '-' + a)  # 加法运算符+拼接
print(f'{r}-{p}-{a}')  # 字符串格式化符f拼接

# 将字符串列表拼接为字符串
print("-".join(['R', 'P', 'A']))  # 输出'R-P-A'

# 字符串还有很多方法，可以使用自带的函数dir来查看字符还有哪些方法
print(dir(lv_str))

# # 列表方法
lv_list1 = ['i', 'S', '-']
lv_list2 = ['R', 'P', 'A']

# 列表拼接
print(lv_list1 + lv_list2)  # 输出['i', 'S', '-', 'R', 'P', 'A']

words: list = list("iS-RPA")  # 等同words = ['i', 'S', '-', 'R', 'P', 'A']

# 取、改
words[0], words[len(words) - 1], words[-1]  # 取值'i', 'A', 'A'
words[0] = 'I'  # 修改第一个元素的内容，从'i'改为'I'

# 增、删
words.insert(0, '('), words.append(')')  # 首、尾添加元素
words.remove('S'), words.pop(0)  # 按“值、索引”删除其中1个元素

# 排序
sorted(words, reverse=False)  # 正、反排序，reverse默认为True（正序）
list(reversed(words))  # 颠倒顺序，并不排序

# 切片，从开始到结尾前（不含结尾，遵守衔接规则）
words: list = list("iS-RPA")
print(words[0:2], words[2:4], words[4:6])
# ['i', 'S']    ['-', 'R']      ['P', 'A']
print(words[0:6:2])  # 往后2个索引取一次值，['i', '-', 'P']

# # 字典方法
words: dict = dict(R=0, P=1, A=2)  # 等同words = {'R': 0, 'P': 1, 'A': 2}
# 字典是无序的，不支持切片，且key不能是可变数据（比如：{[1,2,3]: 'ABC'}）
words['C'] = 3, words.pop('C', 3)  # 添加和删除元素
print(words['C']), words.get('C', 3)  # 取值，建议使用get方法（key不存在就返回默认值3）
words.update({"R": 1, "C": 4})  # 更新字典{'R': 1, 'P': 1, 'A': 2, 'C': 4}
print(words.keys(), words.values())  # 获取所有key和所有value
# ['R', 'P', 'A', 'C']  [1, 1, 2, 4]
list(words.items())  # 成对获取key和value，[('S', 0), ('N', 1), ('P', 2)]

# # RPA流程制作中常用的模块简述

# `open`函数读写文本文件
# 常用来在运行过程中存储中间过程数据
# 文件有很多打开模式，一般是读（r）和写（w），更多模式查看此链接
# https://www.runoob.com/python/file-methods.html

# 创建一个1.txt文件并写入'abc'字符串
with open('1.txt', 'w') as fp:
    fp.write("abc")

# 读取1.txt文件
with open('1.txt', 'r') as fp:
    print(fp.read())

# 常用的读是r+模式（避免文件不存在而读取报错）；
# 追加写入a+模式（项目过程变量追加存储）

# os.path模块
import os

# 拼接文件路径：'C:\\work\\a.doc'
path = os.path.join('C:\\', 'work', 'a.doc')

# 拆分出：目录、文件
directory, file = os.path.split(path)  # ('C:\\work', 'a.doc')
# 等同于：
directory = os.path.dirname(path)  # 'C:\\work'
file = os.path.basename(path)  # 'a.doc'

# 拆分出文件的名称和扩展名
file_name, extension_name = os.path.splitext(file)  # 'a', '.doc'

# 路径是否存在，文件、文件夹
os.path.exists(path)  # 返回True存在、False不存在

# 判断路径是否文件夹或文件，前提是路径要存在，不存在都是False
os.path.isdir(path)
os.path.isfile(path)

# time模块
# 常用于计算时间戳和延时执行
import time

start_time = time.time()  # 获取当前时间戳
time.sleep(2)  # 延时2秒执行接下来的语句
print(time.time() - start_time)  # 计算运行时长，大约是2秒多一点

# datetime与dateutil模块
# 常用来在RPA设计器中获取日期和时间，以及格式化日期和时间
from datetime import datetime
from dateutil.parser import parse

# 当前日期时间
now = datetime.now()
print(now.date(), now.time())

# 日期时间格式化显示，更多格式化字符含义，查看此链接
# https://www.runoob.com/python/python-date-time.html
print(now.strftime('%Y-%m-%d %H:%M:%S'))

# 日期字符串，转为日期对象（datetime），格式不对应会报错
dt = datetime.strptime('2023-01-01 00:30:59', '%Y-%m-%d %H:%M:%S')

# 使用dateutil模块快速解析出日期对象（datetime）
print(parse('2023-01-01 00:30:59'))
print(parse('2023-01-01 00:30'))
print(parse('2023-01-01'))

# 日期间比较
print(parse('2023-01-01') > parse('2023-01-02'))

# `json`模块
import json

json_str = """
{
    "a": 1,
    "b": 2,
    "c": 3
}
"""
# 将json字符串转为dict字典类型数据
data = json.loads(json_str)
print(data)  # 输出：{'a': 1, 'b': 2, 'c': 3}

# 将dict字典转换为json字符串
data_json = json.dumps(data)
print(data_json)  # 输出：'{"a": 1, "b": 2, "c": 3}'

# `pandas.DataFrame`模块
# DataFrame有点类似于excel的数据表格，更多内容浏览该链接：
# https://www.runoob.com/pandas/pandas-tutorial.html

import pandas as pd

# 创建一个DataFrame数据
df = pd.DataFrame(
    data=[[1, 1, 1], [2, 2, 2], [3, 3, 3]],
    columns=['a', 'b', 'c']
)
print(df)

# 取出一列转为列表
print(df["a"].to_list())

# 新增一列
df["d"] = [4, 4, 4]
print(df)

# 取出第一行转为列表，行从0开始计数
print(df.loc[0].to_list())

# 取出（第三行，b列）单元格内容
print(df.loc[2, 'b'])  # 输出：3

# 导出为excel表格
df.to_excel("1.xlsx", index=False)

# 从excel导入数据为DataFrame
df = pd.read_excel("1.xlsx")
print(df)


# # 全局变量使用时为什么是self.开头？（对象声明与实例化）
# 如何声明一个类？
class NewProject2023a:
    """一个RPA新项目"""

    def __init__(self):
        """初始化方法
        固定参数叫self，表示类自己
        """
        # 定义类属性（也就是RPA的全局变量）
        self.path = __file__

    def main(self):
        """主方法，一般方法名称小写开头
        在每一个方法中都可以使用类本身（self）的属性（变量）
        """
        lv_1 = 1
        print(lv_1)
        # 使用self.来访问类属性
        print(self.path)


# 类的更多信息，查看链接：https://zhuanlan.zhihu.com/p/426006204


# 实例化对象
pro = NewProject2023a()

# 调用类方法（与函数区分）和属性
pro.main()
print(pro.path)
